為什麼要用 Vue 3 Composition API?
對我來說最重要的有2點:
- 比Options API更好整理邏輯
- 可以重複使用
- 完全搭配Typescript
可以在官方文檔看更多:Why Composition Api
今天就來一次把Composition API的重點看完,
我這邊主要使用:Composition API + Typescript
,並以SFC
(單文件主見)為主。
這一篇也變成我的筆記方便回來查找。
目前完成的有(隨時更新):
Data: Reactive & Ref
Method
Computed
Watch (WatchEffect待補)
Props
Emits
Styles
Lifecycle
下面有部分是自己用英文作的筆記,(來不及翻譯就抱歉啦)
環遊非洲第08天:非洲101 之Q
猜猜看如果你在肯亞使用塑膠袋會發生什麼事情?
A. 會有小孩跟你要塑膠袋
B. 會有人要跟你合照
C. 必須繳交罰款
D. 什麼事情都不會發生
官方推薦以<script setup>
作為 Single-File Components (SFCs)的語法
範例:
<template>
<button @click="log">{{ msg }}</button>
</template>
<script lang="ts" setup>
// variable
const msg = 'Hello!';
// functions
function log() {
console.log(msg)
}
</script>
<style lang="scss" scoped>
.button
background: black;
</style>
Composition API使用reactive
或是ref
來追蹤數據的變化
(如同Options API data的作用)
使用reactive
追蹤物件和陣列變化,
而ref
可以用在各種類型
官方文檔: https://vuejs.org/guide/essentials/reactivity-fundamentals.html
表格快速看用法:
reactive() | ref() | |
---|---|---|
用法 | Objects, arrays, and collection types such as Map and Set. ⚠️It cannot hold primitive types such as string, number or boolean. ⚠️ Reactive objects are JavaScript Proxies, which are not equal to the original object. | Can hold any value type. When holding object types, ref automatically converts its .value with reactive() |
語法 | import {reactive} from 'vue' const state = reactive({count: 0}) |
import {ref} from 'vue' const state = ref(0) |
取值 | function increment() {state.count++ } |
Argument will be wrapped with .value property function increment() {count.value++} |
Template裡面用法 | {{ state.count }} |
在template裡面value會自動被拆掉,所以不用表明.value {{ count }} |
⚠️Reactive的Array裡面也都是Proxy,使用展開符號取得裡面的值(TODO: 驗證)
const myCountries = reactive([{name: 'Kenya'}, {name: 'South Africa'}])
console.log(myCountries) // [Proxy, Proxy]
console.log(...myCountries) // [{...},{...}]
使用函式宣告式:
function iconURL(name: string): string {
return `/img/weather/${name}.png`;
}
//basic usage
const double = computed(() => {
return something;
});
//declare return type
const double = computed<number>(() => {
// type error if this doesn't return a number
});
Computed回傳的也是一個computed ref
(Proxy),
需要使用.value
來取得值
在Template也會被自動解析,不需要使用.value屬性
//Access inside the template
<template>
<div>
{{ double }}
</div>
</template>
//Access computed value inside other functions with .value
function getValue(){
double.value + ...
}
import {ref,watch} from 'vue'
const x = ref(0)
const y = ref(0)
// watch a ref
watch(x, (newQuestion, oldQuestion) => {
...
})
//Watch a property of reactive object
const obj = reactive({ count: 0 })
//要觀察Object或Array的話,使用getter
//Use a getter
watch(() => obj.count,(count) => {
console.log(`count is: ${count}`)
}
)
Use defineProps macro with object syntax inside
Two types of declaration:
- Run-time declartion
- 2.Type-based prop declaration
When using type declaration, the equivalent runtime declaration is automatically generated
See also: https://vuejs.org/guide/components/props.html
https://vuejs.org/guide/components/props.html
//no need to import defineProps
//1.Run-time declartion
const prop = defineProps({
propA: {
type: String,
required: true
default: ''
},
})
//2.Type-based prop declaration
// https://vuejs.org/api/sfc-script-setup.html#default-props-values-when-using-type-declaration
export interface Props {
msg: string
labels?: string[]
}
const props = defineProps<Props>();
//with default value(實驗階段)
const props = withDefaults(defineProps<Props>(), {
msg: 'hello',
labels: () => ['one', 'two']
})
//Access props (same in templates & functions)
const props = defineProps({
propA: Boolean
})
console.log(props.propA)
See also: https://vuejs.org/guide/components/events.html
//no need to import defineEmits
const emit = defineEmits(['searchCleared']);
//待補:emit型別宣告
//Use in functions
function buttonClick() {
emit('submit')
}
//Use in template
<template>
<button @click="$emit('someEvent')">click me</button>
</template>
Callbacks called when the stage is completed
Composition API: Lifecycle Hooks
import {onMounted, onUpdated, onUnmounted} from 'vue';
onMounted(() => {
//
})
** 官方推薦使用Pinia,有機會會回來補充Pinia
import { useStore } from 'vuex'
export default {
setup () {
const store = useStore()
}
}
store.state.count
store.getters.double
store.commit('increment')
store.dispatch('asyncIncrement')
When trying to change child-component styles, you can use :deep(selector)
<style lang="sass" scoped>
.select-rows
:deep(.v-field)
font-size: 12px
</style>
環遊非洲第08天:非洲101 之A
C. 必須繳交罰款,可能高達上萬元,不然會被關起來喔!
因為肯亞是世界上禁塑膠袋最嚴格的國家之一。據說海關也會檢查你的包包有沒有塑膠袋(很快就可以去肯亞幫大家證實一下了)
其實整個非洲大陸,是禁塑環保的前段班,
盧安達、模里西斯等國家也都禁止塑膠袋,而南非和其他國家,則禁止商家提供免費塑膠袋。
是不是和我們對非洲的印象很不一樣呢?
Planet Alert: Africa Leads The Way In Banning The Use Of Plastic
34 Plastic Bans in Africa | A Reality Check
之後就會來幫我們的Options API搬家囉!(順便更新一下UI...)